// Copyright (c) 2024 CHANGLEI. All rights reserved.

import 'dart:async';
import 'dart:ui' as dart_ui;

import 'package:charts_grasp/src/chart/axis/axis.dart';
import 'package:charts_grasp/src/chart/axis/axis_panel.dart';
import 'package:charts_grasp/src/chart/axis/axis_renderer.dart';
import 'package:charts_grasp/src/chart/base/chart_base.dart';
import 'package:charts_grasp/src/chart/base/series_base.dart';
import 'package:charts_grasp/src/chart/chart_segment/chart_segment.dart';
import 'package:charts_grasp/src/chart/chart_series/series.dart';
import 'package:charts_grasp/src/chart/chart_series/series_renderer_properties.dart';
import 'package:charts_grasp/src/chart/common/common.dart';
import 'package:charts_grasp/src/chart/common/interactive_tooltip.dart';
import 'package:charts_grasp/src/chart/common/renderer.dart';
import 'package:charts_grasp/src/chart/series_painter/column_painter.dart';
import 'package:charts_grasp/src/chart/technical_indicators/technical_indicator.dart';
import 'package:charts_grasp/src/chart/user_interaction/crosshair.dart';
import 'package:charts_grasp/src/chart/user_interaction/trackball.dart';
import 'package:charts_grasp/src/chart/user_interaction/trackball_marker_setting_renderer.dart';
import 'package:charts_grasp/src/chart/user_interaction/zooming_panning.dart';
import 'package:charts_grasp/src/chart/utils/enum.dart';
import 'package:charts_grasp/src/common/event_args.dart';
import 'package:charts_grasp/src/common/rendering_details.dart';
import 'package:charts_grasp/src/common/state_properties.dart';
import 'package:charts_grasp/src/common/user_interaction/tooltip.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class CartesianStateProperties extends StateProperties {
  CartesianStateProperties({required this.renderingDetails, required this.chartState})
      : super(renderingDetails, chartState);

  @override
  // ignore: overridden_fields
  final CgCartesianChartState chartState;

  @override
  // ignore: overridden_fields
  late RenderingDetails renderingDetails;

  late Map<AnimationController, VoidCallback> controllerList;

  late Map<String, ValueNotifier<int>> repaintNotifiers;

  late List<ChartAxisRenderer> zoomedAxisRendererStates;

  late List<ChartAxisRenderer> oldAxisRenderers;

  late bool zoomProgress;

  late List<ZoomAxisRange> zoomAxes;

  late List<ChartSegment> selectedSegments;

  late List<ChartSegment> unselectedSegments;

  late List<Rect> renderDatalabelRegions;

  late List<Rect> annotationRegions;

  bool legendRefresh = false;

  DataLabelRenderer? renderDataLabel;

  late CartesianAxisWidget renderOutsideAxis;

  late CartesianAxisWidget renderInsideAxis;

  late List<CartesianSeriesRenderer> oldSeriesRenderers;

  late List<ValueKey<String>?> oldSeriesKeys;

  late List<ChartSegment> segments;

  late List<bool?> oldSeriesVisible;

  bool? zoomedState;

  late List<PointerEvent> touchStartPositions;

  late List<PointerEvent> touchMovePositions;

  late bool enableDoubleTap;
  late bool enableMouseHover;

  bool legendToggling = false;

  dart_ui.Image? backgroundImage;

  dart_ui.Image? legendIconImage;

  bool isTrendlineToggled = false;

  late List<PainterKey> painterKeys;

  late bool triggerLoaded;

  bool rangeChangeBySlider = false;

  bool rangeChangedByChart = false;

  bool isRangeSelectionSlider = false;

  bool? isSeriesLoaded;

  late bool isNeedUpdate;

  late List<CartesianSeriesRenderer> seriesRenderers;

  late ChartAxisPanel chartAxis;

  late ChartSeriesPanel chartSeries;

  late ContainerArea containerArea;

  late bool requireInvertedAxis;

  bool requireAxisTooltip = false;

  bool isTrackballOrientationChanged = false;

  bool isCrosshairOrientationChanged = false;

  Timer? trackballTimer;

  Timer? tooltipTimer;

  bool isTooltipOrientationChanged = false;

  bool isTooltipHidden = false;

  List<ChartPointInfo> chartPointInfo = <ChartPointInfo>[];

  late ZoomPanBehaviorRenderer zoomPanBehaviorRenderer;

  late TrackballBehaviorRenderer trackballBehaviorRenderer;

  late CrosshairBehaviorRenderer crosshairBehaviorRenderer;

  late List<TechnicalIndicatorsRenderer> technicalIndicatorRenderer;

  late TrackballMarkerSettingsRenderer trackballMarkerSettingsRenderer;

  @override
  CgCartesianChart get chart => chartState.widget;

  double seriesDurationFactor = 0.85;

  double trendlineDurationFactor = 0.85;

  late int totalAnimatingSeries;

  late int animationCompleteCount;

  SelectionArgs? selectionArgs;

  bool isTouchUp = false;

  late StateSetter loadMoreViewStateSetter;

  late ChartSwipeDirection swipeDirection;

  Offset? startOffset;
  Offset? currentPosition;

  late bool isRedrawByZoomPan;

  late PointerDeviceKind pointerDeviceKind;

  late bool isLoadMoreIndicator;

  bool canSetRangeController = false;

  Shader? shader;

  int? sideBySideSeriesCount;

  int? sideBySideIndicatorCount;

  late ValueNotifier<int> plotBandRepaintNotifier;

  void setPainterKey(int index, String name, bool renderComplete) {
    int value = 0;
    for (int i = 0; i < painterKeys.length; i++) {
      final PainterKey painterKey = painterKeys[i];
      if (painterKey.isRenderCompleted) {
        value++;
      } else if (painterKey.index == index && painterKey.name == name && !painterKey.isRenderCompleted) {
        painterKey.isRenderCompleted = renderComplete;
        value++;
      }
      if (value >= painterKeys.length && !triggerLoaded) {
        triggerLoaded = true;
      }
    }
  }

  bool get animationCompleted {
    SeriesRendererDetails seriesRendererDetails;
    for (final CartesianSeriesRenderer seriesRenderer in seriesRenderers) {
      seriesRendererDetails = SeriesHelper.getSeriesRendererDetails(seriesRenderer);
      if (seriesRendererDetails.animationController.status == AnimationStatus.forward) {
        return false;
      }
    }
    return true;
  }

  void repaintTrendlines() {
    repaintNotifiers['trendline']!.value++;
  }

  void forwardAnimation(SeriesRendererDetails seriesRendererDetails) {
    final int totalAnimationDuration =
        seriesRendererDetails.series.animationDuration.toInt() + seriesRendererDetails.series.animationDelay!.toInt();
    seriesRendererDetails.animationController.duration = Duration(milliseconds: totalAnimationDuration);
    const double maxSeriesInterval = 0.8;
    double minSeriesInterval = 0.1;
    minSeriesInterval = seriesRendererDetails.series.animationDelay!.toInt() /
            totalAnimationDuration *
            (maxSeriesInterval - minSeriesInterval) +
        minSeriesInterval;
    seriesRendererDetails.seriesAnimation = Tween<double>(begin: 0, end: 1).animate(CurvedAnimation(
      parent: seriesRendererDetails.animationController,
      curve: Interval(minSeriesInterval, maxSeriesInterval, curve: Curves.decelerate),
    ),);
    seriesRendererDetails.seriesElementAnimation = Tween<double>(begin: 0, end: 1).animate(CurvedAnimation(
      parent: seriesRendererDetails.animationController,
      curve: const Interval(0.85, 1, curve: Curves.decelerate),
    ),);
    seriesRendererDetails.animationController.forward(from: 0);
  }

  void redrawByRangeChange() {
    oldAxisRenderers = chartAxis.axisRenderersCollection;
    if (chartState.mounted) {
      // ignore: invalid_use_of_protected_member
      chartState.setState(() {});
    }
  }

  void redraw() {
    oldAxisRenderers = chartAxis.axisRenderersCollection;
    TooltipHelper.getRenderingDetails(renderingDetails.tooltipBehaviorRenderer).timer?.cancel();
    if (TrackballHelper.getRenderingDetails(trackballBehaviorRenderer).trackballPainter?.timer != null) {
      TrackballHelper.getRenderingDetails(trackballBehaviorRenderer).trackballPainter?.timer!.cancel();
    }
    if (renderingDetails.isLegendToggled) {
      segments = <ChartSegment>[];
      oldSeriesVisible = List<bool?>.filled(chartSeries.visibleSeriesRenderers.length, null);
      for (int i = 0; i < chartSeries.visibleSeriesRenderers.length; i++) {
        final CartesianSeriesRenderer seriesRenderer = chartSeries.visibleSeriesRenderers[i];
        final SeriesRendererDetails seriesRendererDetails = SeriesHelper.getSeriesRendererDetails(seriesRenderer);
        if (seriesRenderer is ColumnSeriesRenderer) {
          for (int j = 0; j < seriesRendererDetails.segments.length; j++) {
            segments.add(seriesRendererDetails.segments[j]);
          }
        }
      }
    }
    if (zoomedAxisRendererStates.isNotEmpty) {
      zoomedState = false;
      for (final ChartAxisRenderer axisRenderer in zoomedAxisRendererStates) {
        zoomedState = AxisHelper.getAxisRendererDetails(axisRenderer).zoomFactor != 1;
        if (zoomedState!) {
          break;
        }
      }
    }

    renderingDetails.widgetNeedUpdate = false;

    if (chartState.mounted) {
      // ignore: invalid_use_of_protected_member
      chartState.setState(() {});
    }
  }
}
